package com.shiguiwu.springboot3.filter;

import com.shiguiwu.springboot3.service.TokenBlackService;
import com.shiguiwu.springboot3.service.TokenService;
import com.shiguiwu.springboot3.util.JwtUtils;
import io.jsonwebtoken.Claims;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;
import java.util.List;

@Slf4j
@Component
public class JwtFilter extends OncePerRequestFilter {
    
    @Autowired
    private JwtUtils jwtUtils;
    
    @Autowired
    private TokenService tokenService;

    @Autowired
    private TokenBlackService tokenBlackService;
    
    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                    HttpServletResponse response,
                                    FilterChain chain) throws ServletException, IOException {

        String requestURI = request.getRequestURI();

        // 定义需要放行的Swagger路径列表
        List<String> swaggerPaths = List.of(
                "/swagger-ui.html",
                "/swagger-ui/index.html",
                "/swagger-ui/",
                "/swagger-ui/**",
                "/v3/api-docs",
                "/v3/api-docs/**",
                "/swagger-resources",
                "/swagger-resources/**",
                "/configuration/ui",
                "/configuration/security",
                "/favicon.ico",
                "/.well-known/**",
                "/webjars/**","/auth/register","/error"
        );

        log.info("当前地址 ============>>>{}", requestURI);
        // 检查当前请求是否需要放行
        boolean shouldSkip = swaggerPaths.stream().anyMatch(path -> {
            // 这里可以使用AntPathMatcher进行更复杂的匹配，简单情况也可以用startsWith
            return requestURI.startsWith(path.replace("/**", ""));
        });

        if (shouldSkip) {
            // 如果是Swagger路径，直接放行，不进行JWT验证
            chain.doFilter(request, response);
            return;
        }
        log.info("当前地址1 ============>>>{}", requestURI);
        // 跳过登录和刷新接口
        if (request.getServletPath().equals("/auth/login") || 
            request.getServletPath().equals("/auth/refresh")) {
            chain.doFilter(request, response);
            return;
        }


        // 从请求头获取Token
        final String authHeader = request.getHeader("Authorization");
        String token = null;
        String jwt = null;
        
        if (authHeader != null && authHeader.startsWith("Bearer ")) {
            jwt = authHeader.substring(7);
            token = jwtUtils.extractToken(jwt);
        }

        if (jwtUtils.isTokenExpired(jwt)) {
            response.setStatus(HttpStatus.UNAUTHORIZED.value());
            response.getWriter().write("Token is expired");
            return;
        }
        
        // 验证Token有效性
        if (token != null && SecurityContextHolder.getContext().getAuthentication() == null) {
            UserDetails userDetails = tokenService.getToken(token);
            
            if (jwtUtils.validateToken(jwt)) {

                String tokenId = jwtUtils.extractClaim(jwt, Claims::getId);
                // 检查Token是否在黑名单中
                if (tokenBlackService.isBlacklisted(tokenId)) {
                    response.setStatus(HttpStatus.UNAUTHORIZED.value());
                    response.getWriter().write("Token has been invalidated");
                    return;
                }
                UsernamePasswordAuthenticationToken authToken =
                    new UsernamePasswordAuthenticationToken(userDetails, null, 
                                                          userDetails.getAuthorities());
                authToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                SecurityContextHolder.getContext().setAuthentication(authToken);
            }
        }
        
        chain.doFilter(request, response);
    }
}